 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  * Benjamin Muskalla - bug 105041
  *******************************************************************************/

 package org.eclipse.ui.views.navigator;

 import java.util.ArrayList ;
 import java.util.Arrays ;
 import java.util.Iterator ;
 import java.util.List ;

 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jface.action.IMenuListener;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
 import org.eclipse.jface.viewers.DecoratingLabelProvider;
 import org.eclipse.jface.viewers.DoubleClickEvent;
 import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ILabelDecorator;
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.jface.viewers.IOpenListener;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.OpenEvent;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.ViewerComparator;
 import org.eclipse.jface.viewers.ViewerSorter;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.dnd.DND;
 import org.eclipse.swt.dnd.FileTransfer;
 import org.eclipse.swt.dnd.Transfer;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.KeyListener;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.IPartListener;
 import org.eclipse.ui.IViewSite;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchPreferenceConstants;
 import org.eclipse.ui.IWorkingSet;
 import org.eclipse.ui.IWorkingSetManager;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.ResourceWorkingSetFilter;
 import org.eclipse.ui.actions.ActionContext;
 import org.eclipse.ui.actions.OpenResourceAction;
 import org.eclipse.ui.ide.ResourceUtil;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.views.navigator.ResourceNavigatorMessages;
 import org.eclipse.ui.model.WorkbenchContentProvider;
 import org.eclipse.ui.model.WorkbenchLabelProvider;
 import org.eclipse.ui.part.ISetSelectionTarget;
 import org.eclipse.ui.part.IShowInSource;
 import org.eclipse.ui.part.IShowInTarget;
 import org.eclipse.ui.part.PluginTransfer;
 import org.eclipse.ui.part.ResourceTransfer;
 import org.eclipse.ui.part.ShowInContext;
 import org.eclipse.ui.part.ViewPart;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.eclipse.ui.views.framelist.FrameList;
 import org.eclipse.ui.views.framelist.TreeFrame;

 /**
  * Implements the Resource Navigator view.
  */
 public class ResourceNavigator extends ViewPart implements ISetSelectionTarget,
         IResourceNavigator {

     private TreeViewer viewer;

     private IDialogSettings settings;

     private IMemento memento;

     private FrameList frameList;

     private ResourceNavigatorActionGroup actionGroup;

     private ResourcePatternFilter patternFilter = new ResourcePatternFilter();

     private ResourceWorkingSetFilter workingSetFilter = new ResourceWorkingSetFilter();

     private boolean linkingEnabled;

     private boolean dragDetected;

     private Listener dragDetectListener;
     /**
      * Remembered working set.
      */
     private IWorkingSet workingSet;

     /**
      * Marks whether the working set we're using is currently empty. In this
      * event we're effectively not using a working set.
      */
     private boolean emptyWorkingSet = false;
     
     /**
      * Settings constant for section name (value <code>ResourceNavigator</code>).
      */
     private static final String STORE_SECTION = "ResourceNavigator"; //$NON-NLS-1$

     /**
      * Settings constant for sort order (value <code>ResourceViewer.STORE_SORT_TYPE</code>).
      */
     private static final String STORE_SORT_TYPE = "ResourceViewer.STORE_SORT_TYPE"; //$NON-NLS-1$

     /**
      * Settings constant for working set (value <code>ResourceWorkingSetFilter.STORE_WORKING_SET</code>).
      */
     private static final String STORE_WORKING_SET = "ResourceWorkingSetFilter.STORE_WORKING_SET"; //$NON-NLS-1$

     /**
      * @deprecated No longer used but preserved to avoid an api change.
      */
     public static final String NAVIGATOR_VIEW_HELP_ID = INavigatorHelpContextIds.RESOURCE_VIEW;

     /**
      * True iff we've already scheduled an asynchronous call to linkToEditor
      */
     private boolean linkScheduled = false;
     
     // Persistance tags.
 private static final String TAG_SORTER = "sorter"; //$NON-NLS-1$

     private static final String TAG_FILTERS = "filters"; //$NON-NLS-1$

     private static final String TAG_FILTER = "filter"; //$NON-NLS-1$

     private static final String TAG_SELECTION = "selection"; //$NON-NLS-1$

     private static final String TAG_EXPANDED = "expanded"; //$NON-NLS-1$

     private static final String TAG_ELEMENT = "element"; //$NON-NLS-1$

     private static final String TAG_IS_ENABLED = "isEnabled"; //$NON-NLS-1$

     private static final String TAG_PATH = "path"; //$NON-NLS-1$

     private static final String TAG_CURRENT_FRAME = "currentFrame"; //$NON-NLS-1$

     private IPartListener partListener = new IPartListener() {
         public void partActivated(IWorkbenchPart part) {
             if (part instanceof IEditorPart) {
                 editorActivated((IEditorPart) part);
             }
         }

         public void partBroughtToTop(IWorkbenchPart part) {
         }

         public void partClosed(IWorkbenchPart part) {
         }

         public void partDeactivated(IWorkbenchPart part) {
         }

         public void partOpened(IWorkbenchPart part) {
         }
     };

     private IPropertyChangeListener propertyChangeListener = new IPropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent event) {
             String property = event.getProperty();
             Object newValue = event.getNewValue();
             Object oldValue = event.getOldValue();
            
             if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property)
                     && oldValue == workingSet) {
                 setWorkingSet(null);
             } else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE
                     .equals(property)
                     && newValue == workingSet) {
                 updateTitle();
             } else if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE
                     .equals(property)
                     && newValue == workingSet) {
                 if (workingSet.isAggregateWorkingSet() && workingSet.isEmpty()) {
                     // act as if the working set has been made null
 if (!emptyWorkingSet) {
                         emptyWorkingSet = true;
                         workingSetFilter.setWorkingSet(null);
                     }
                 } else {
                     // we've gone from empty to non-empty on our set.
 // Restore it.
 if (emptyWorkingSet) {
                         emptyWorkingSet = false;
                         workingSetFilter.setWorkingSet(workingSet);
                     }
                 }
                 getViewer().refresh();
             }
         }
     };

     /**
      * Constructs a new resource navigator view.
      */
     public ResourceNavigator() {
         IDialogSettings viewsSettings = getPlugin().getDialogSettings();

         settings = viewsSettings.getSection(STORE_SECTION);
         if (settings == null) {
             settings = viewsSettings.addNewSection(STORE_SECTION);
         }

         initLinkingEnabled();
     }

     /**
      * Converts the given selection into a form usable by the viewer,
      * where the elements are resources.
      */
     private StructuredSelection convertSelection(ISelection selection) {
         ArrayList list = new ArrayList ();
         if (selection instanceof IStructuredSelection) {
             IStructuredSelection ssel = (IStructuredSelection) selection;
             for (Iterator i = ssel.iterator(); i.hasNext();) {
                 Object o = i.next();
                 IResource resource = null;
                 if (o instanceof IResource) {
                     resource = (IResource) o;
                 } else {
                     if (o instanceof IAdaptable) {
                         resource = (IResource) ((IAdaptable) o)
                                 .getAdapter(IResource.class);
                     }
                 }
                 if (resource != null) {
                     list.add(resource);
                 }
             }
         }
         return new StructuredSelection(list);
     }

     /* (non-Javadoc)
      * Method declared on IWorkbenchPart.
      */
     public void createPartControl(Composite parent) {
         TreeViewer viewer = createViewer(parent);
         this.viewer = viewer;

         if (memento != null) {
             restoreFilters();
             restoreLinkingEnabled();
         }
         frameList = createFrameList();
         initDragAndDrop();
         updateTitle();

         initContextMenu();

         initResourceComparator();
         initWorkingSetFilter();

         // make sure input is set after sorters and filters,
 // to avoid unnecessary refreshes
 viewer.setInput(getInitialInput());

         // make actions after setting input, because some actions
 // look at the viewer for enablement (e.g. the Up action)
 makeActions();

         // Fill the action bars and update the global action handlers'
 // enabled state to match the current selection.
 getActionGroup().fillActionBars(getViewSite().getActionBars());
         updateActionBars((IStructuredSelection) viewer.getSelection());

         getSite().setSelectionProvider(viewer);
         getSite().getPage().addPartListener(partListener);
         IWorkingSetManager workingSetManager = getPlugin().getWorkbench()
                 .getWorkingSetManager();
         workingSetManager.addPropertyChangeListener(propertyChangeListener);

         if (memento != null) {
             restoreState(memento);
         }
         memento = null;

         // Set help for the view
 getSite().getWorkbenchWindow().getWorkbench().getHelpSystem().setHelp(
                 viewer.getControl(), getHelpContextId());
     }

     /**
      * Returns the help context id to use for this view.
      *
      * @since 2.0
      */
     protected String getHelpContextId() {
         return INavigatorHelpContextIds.RESOURCE_VIEW;
     }

     /**
      * Initializes and registers the context menu.
      *
      * @since 2.0
      */
     protected void initContextMenu() {
         MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
 menuMgr.setRemoveAllWhenShown(true);
         menuMgr.addMenuListener(new IMenuListener() {
             public void menuAboutToShow(IMenuManager manager) {
                 ResourceNavigator.this.fillContextMenu(manager);
             }
         });
         TreeViewer viewer = getTreeViewer();
         Menu menu = menuMgr.createContextMenu(viewer.getTree());
         viewer.getTree().setMenu(menu);
         getSite().registerContextMenu(menuMgr, viewer);
     }

     /**
      * Creates the viewer.
      *
      * @param parent the parent composite
      * @since 2.0
      */
     protected TreeViewer createViewer(Composite parent) {
         TreeViewer viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
                 | SWT.V_SCROLL);
         viewer.setUseHashlookup(true);
         initContentProvider(viewer);
         initLabelProvider(viewer);
         initFilters(viewer);
         initListeners(viewer);

         return viewer;
     }

     /**
      * Sets the content provider for the viewer.
      *
      * @param viewer the viewer
      * @since 2.0
      */
     protected void initContentProvider(TreeViewer viewer) {
         viewer.setContentProvider(new WorkbenchContentProvider());
     }

     /**
      * Sets the label provider for the viewer.
      *
      * @param viewer the viewer
      * @since 2.0
      */
     protected void initLabelProvider(TreeViewer viewer) {
         viewer.setLabelProvider(new DecoratingLabelProvider(
                 new WorkbenchLabelProvider(), getPlugin().getWorkbench()
                         .getDecoratorManager().getLabelDecorator()));
     }

     /**
      * Adds the filters to the viewer.
      *
      * @param viewer the viewer
      * @since 2.0
      */
     protected void initFilters(TreeViewer viewer) {
         viewer.addFilter(patternFilter);
         viewer.addFilter(workingSetFilter);
     }

     /**
      * Initializes the linking enabled setting from the preference store.
      */
     private void initLinkingEnabled() {
         // Try the dialog settings first, which remember the last choice.
 String setting = settings
                 .get(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
         if (setting != null) {
             linkingEnabled = setting.equals("true"); //$NON-NLS-1$
 return;
         }
         // If not in the dialog settings, check the preference store for the default setting.
 // Use the UI plugin's preference store since this is a public preference.
 linkingEnabled = PlatformUI.getPreferenceStore().getBoolean(
                 IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
     }

     /**
      * Adds the listeners to the viewer.
      *
      * @param viewer the viewer
      * @since 2.0
      */
     protected void initListeners(TreeViewer viewer) {
         viewer.addSelectionChangedListener(new ISelectionChangedListener() {
             public void selectionChanged(SelectionChangedEvent event) {
                 handleSelectionChanged(event);
             }
         });
         viewer.addDoubleClickListener(new IDoubleClickListener() {
             public void doubleClick(DoubleClickEvent event) {
                 handleDoubleClick(event);
             }
         });
         viewer.addOpenListener(new IOpenListener() {
             public void open(OpenEvent event) {
                 handleOpen(event);
             }
         });
         viewer.getControl().addKeyListener(new KeyListener() {
             public void keyPressed(KeyEvent event) {
                 handleKeyPressed(event);
             }

             public void keyReleased(KeyEvent event) {
                 handleKeyReleased(event);
             }
         });
     }

     /* (non-Javadoc)
      * Method declared on IWorkbenchPart.
      */
     public void dispose() {
         getSite().getPage().removePartListener(partListener);

         IWorkingSetManager workingSetManager = getPlugin().getWorkbench()
                 .getWorkingSetManager();
         workingSetManager.removePropertyChangeListener(propertyChangeListener);

         if (getActionGroup() != null) {
             getActionGroup().dispose();
         }
         Control control = viewer.getControl();
         if (dragDetectListener != null && control != null
                 && control.isDisposed() == false) {
             control.removeListener(SWT.DragDetect, dragDetectListener);
         }
         super.dispose();
     }

     /**
      * An editor has been activated. Sets the selection in this navigator
      * to be the editor's input, if linking is enabled.
      *
      * @param editor the active editor
      * @since 2.0
      */
     protected void editorActivated(IEditorPart editor) {
         if (!isLinkingEnabled()) {
             return;
         }

         IFile file = ResourceUtil.getFile(editor.getEditorInput());
         if (file != null) {
             ISelection newSelection = new StructuredSelection(file);
             if (getTreeViewer().getSelection().equals(newSelection)) {
                 getTreeViewer().getTree().showSelection();
             } else {
                 getTreeViewer().setSelection(newSelection, true);
             }
         }
     }

     /**
      * Called when the context menu is about to open.
      * Delegates to the action group using the viewer's selection as the action context.
      * @since 2.0
      */
     protected void fillContextMenu(IMenuManager menu) {
         IStructuredSelection selection = (IStructuredSelection) getViewer()
                 .getSelection();
         getActionGroup().setContext(new ActionContext(selection));
         getActionGroup().fillContextMenu(menu);
     }

     /*
      * @see IResourceNavigatorPart
      * @since 2.0
      */
     public FrameList getFrameList() {
         return frameList;
     }

     /**
      * Returns the initial input for the viewer.
      * Tries to convert the page input to a resource, either directly or via IAdaptable.
      * If the resource is a container, it uses that.
      * If the resource is a file, it uses its parent folder.
      * If a resource could not be obtained, it uses the workspace root.
      *
      * @since 2.0
      */
     protected IAdaptable getInitialInput() {
         IAdaptable input = getSite().getPage().getInput();
         if (input != null) {
             IResource resource = null;
             if (input instanceof IResource) {
                 resource = (IResource) input;
             } else {
                 resource = (IResource) input.getAdapter(IResource.class);
             }
             if (resource != null) {
                 switch (resource.getType()) {
                 case IResource.FILE:
                     return resource.getParent();
                 case IResource.FOLDER:
                 case IResource.PROJECT:
                 case IResource.ROOT:
                     return resource;
                 default:
                     // Unknown resource type. Fall through.
 break;
                 }
             }
         }
         return ResourcesPlugin.getWorkspace().getRoot();
     }

     /**
      * Returns the pattern filter for this view.
      *
      * @return the pattern filter
      * @since 2.0
      */
     public ResourcePatternFilter getPatternFilter() {
         return this.patternFilter;
     }

     /**
      * Returns the working set for this view.
      *
      * @return the working set
      * @since 2.0
      */
     public IWorkingSet getWorkingSet() {
         return workingSetFilter.getWorkingSet();
     }

     /**
      * Returns the navigator's plugin.
      * @return the UI plugin for this bundle
      */
     public AbstractUIPlugin getPlugin() {
         return IDEWorkbenchPlugin.getDefault();
     }

     /**
      * Return the sorter.
      *
      * @since 2.0
      * @deprecated as of 3.3, use {@link ResourceNavigator#getComparator()}
      */
     public ResourceSorter getSorter() {
         return (ResourceSorter) getTreeViewer().getSorter();
     }

     /**
      * Returns the comparator.
      *
      * @return the <code>ResourceComparator</code>
      * @since 3.3
      */

     public ResourceComparator getComparator(){
         return (ResourceComparator) getTreeViewer().getComparator();
     }
     /**
      * Returns the resource viewer which shows the resource hierarchy.
      * @since 2.0
      */
     public TreeViewer getViewer() {
         return viewer;
     }

     /**
      * Returns the tree viewer which shows the resource hierarchy.
      * @return the tree viewer
      * @since 2.0
      */
     public TreeViewer getTreeViewer() {
         return viewer;
     }

     /**
      * Returns the shell to use for opening dialogs.
      * Used in this class, and in the actions.
      *
      * @return the shell
      * @deprecated use getViewSite().getShell()
      */
     public Shell getShell() {
         return getViewSite().getShell();
     }

     /**
      * Returns the message to show in the status line.
      *
      * @param selection the current selection
      * @return the status line message
      * @since 2.0
      */
     protected String getStatusLineMessage(IStructuredSelection selection) {
         if (selection.size() == 1) {
             Object o = selection.getFirstElement();
             if (o instanceof IResource) {
                 return ((IResource) o).getFullPath().makeRelative().toString();
             }
             return ResourceNavigatorMessages.ResourceNavigator_oneItemSelected;
         }
         if (selection.size() > 1) {
             return NLS.bind(ResourceNavigatorMessages.ResourceNavigator_statusLine, String.valueOf(selection.size()));
         }
         return ""; //$NON-NLS-1$
 }

     /**
      * Returns the name for the given element.
      * Used as the name for the current frame.
      */
     String getFrameName(Object element) {
         if (element instanceof IResource) {
             return ((IResource) element).getName();
         }
         String text = ((ILabelProvider) getTreeViewer().getLabelProvider())
         .getText(element);
         if(text == null) {
             return "";//$NON-NLS-1$
 }
         return text;
     }

     /**
      * Returns the tool tip text for the given element.
      * Used as the tool tip text for the current frame, and for the view title tooltip.
      */
     String getFrameToolTipText(Object element) {
         if (element instanceof IResource) {
             IPath path = ((IResource) element).getFullPath();
             if (path.isRoot()) {
                 return ResourceNavigatorMessages.ResourceManager_toolTip;
             }
             return path.makeRelative().toString();
         }
         
         String text = ((ILabelProvider) getTreeViewer().getLabelProvider())
             .getText(element);
         if(text == null) {
             return "";//$NON-NLS-1$
 }
         return text;
     }

     /**
      * Handles an open event from the viewer.
      * Opens an editor on the selected file.
      *
      * @param event the open event
      * @since 2.0
      */
     protected void handleOpen(OpenEvent event) {
         IStructuredSelection selection = (IStructuredSelection) event
                 .getSelection();
         getActionGroup().runDefaultAction(selection);
     }

     /**
      * Handles a double-click event from the viewer.
      * Expands or collapses a folder when double-clicked.
      *
      * @param event the double-click event
      * @since 2.0
      */
     protected void handleDoubleClick(DoubleClickEvent event) {
         IStructuredSelection selection = (IStructuredSelection) event
                 .getSelection();
         Object element = selection.getFirstElement();

         // 1GBZIA0: ITPUI:WIN2000 - Double-clicking in navigator should expand/collapse containers
 TreeViewer viewer = getTreeViewer();
         if (viewer.isExpandable(element)) {
             viewer.setExpandedState(element, !viewer.getExpandedState(element));
         } else if (selection.size() == 1 && (element instanceof IResource)
                 && ((IResource) element).getType() == IResource.PROJECT) {
             OpenResourceAction ora = new OpenResourceAction(getSite()
                     .getShell());
             ora.selectionChanged((IStructuredSelection) viewer.getSelection());
             if (ora.isEnabled()) {
                 ora.run();
             }
         }

     }

     /**
      * Handles a selection changed event from the viewer.
      * Updates the status line and the action bars, and links to editor (if option enabled).
      *
      * @param event the selection event
      * @since 2.0
      */
     protected void handleSelectionChanged(SelectionChangedEvent event) {
         final IStructuredSelection sel = (IStructuredSelection) event
                 .getSelection();
         updateStatusLine(sel);
         updateActionBars(sel);
         dragDetected = false;
         if (isLinkingEnabled() && !linkScheduled) {
             // Ensure that if another selection change arrives while we're waiting for the *syncExec,
 // we only do this work once.
 linkScheduled = true;
             getShell().getDisplay().asyncExec(new Runnable () {
                 public void run() {
                     // There's no telling what might have changed since the syncExec was scheduled.
 // Check to make sure that the widgets haven't been disposed.
 linkScheduled = false;
                     
                     if (viewer == null || viewer.getControl() == null || viewer.getControl().isDisposed()) {
                         return;
                     }
                     
                     if (dragDetected == false) {
                         ISelection sel = viewer.getSelection();
                         if (sel instanceof IStructuredSelection) {
                             IStructuredSelection selection = (IStructuredSelection)sel;
                         
                             // only synchronize with editor when the selection is not the result
 // of a drag. Fixes bug 22274.
 linkToEditor(selection);
                         }
                     }
                 }
             });
         }
     }

     /**
      * Handles a key press event from the viewer.
      * Delegates to the action group.
      *
      * @param event the key event
      * @since 2.0
      */
     protected void handleKeyPressed(KeyEvent event) {
         getActionGroup().handleKeyPressed(event);
     }

     /**
      * Handles a key release in the viewer. Does nothing by default.
      *
      * @param event the key event
      * @since 2.0
      */
     protected void handleKeyReleased(KeyEvent event) {
     }

     /* (non-Javadoc)
      * Method declared on IViewPart.
      */
     public void init(IViewSite site, IMemento memento) throws PartInitException {
         super.init(site, memento);
         this.memento = memento;
     }

     /**
      * Adds drag and drop support to the navigator.
      *
      * @since 2.0
      */
     protected void initDragAndDrop() {
         int ops = DND.DROP_COPY | DND.DROP_MOVE;
         Transfer[] transfers = new Transfer[] {
                 LocalSelectionTransfer.getInstance(),
                 ResourceTransfer.getInstance(), FileTransfer.getInstance(),
                 PluginTransfer.getInstance() };
         TreeViewer viewer = getTreeViewer();
         viewer.addDragSupport(ops, transfers, new NavigatorDragAdapter(viewer));
         NavigatorDropAdapter adapter = new NavigatorDropAdapter(viewer);
         adapter.setFeedbackEnabled(false);
         viewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, adapter);
         dragDetectListener = new Listener() {
             public void handleEvent(Event event) {
                 dragDetected = true;
             }
         };
         viewer.getControl().addListener(SWT.DragDetect, dragDetectListener);
     }

     /**
      * Creates the frame source and frame list, and connects them.
      *
      * @since 2.0
      */
     protected FrameList createFrameList() {
         NavigatorFrameSource frameSource = new NavigatorFrameSource(this);
         FrameList frameList = new FrameList(frameSource);
         frameSource.connectTo(frameList);
         return frameList;
     }

     /**
      * Initializes the sorter.
      *
      * @deprecated as of 3.3, use {@link ResourceNavigator#initResourceComparator()} instead
      */
     protected void initResourceSorter() {
         int sortType = ResourceSorter.NAME;
         try {
             int sortInt = 0;
             if (memento != null) {
                 String sortStr = memento.getString(TAG_SORTER);
                 if (sortStr != null) {
                     sortInt = new Integer (sortStr).intValue();
                 }
             } else {
                 sortInt = settings.getInt(STORE_SORT_TYPE);
             }
             if (sortInt == ResourceSorter.NAME
                     || sortInt == ResourceSorter.TYPE) {
                 sortType = sortInt;
             }
         } catch (NumberFormatException e) {
         }
         setSorter(new ResourceSorter(sortType));
     }
     
     /**
      * Initializes the comparator.
      * @since 3.3
      */
     protected void initResourceComparator(){
         int sortType = ResourceComparator.NAME;
         try {
             int sortInt = 0;
             if (memento != null) {
                 String sortStr = memento.getString(TAG_SORTER);
                 if (sortStr != null) {
                     sortInt = new Integer (sortStr).intValue();
                 }
             } else {
                 sortInt = settings.getInt(STORE_SORT_TYPE);
             }
             if (sortInt == ResourceComparator.NAME
                     || sortInt == ResourceComparator.TYPE) {
                 sortType = sortInt;
             }
         } catch (NumberFormatException e) {
         }
         setComparator(new ResourceComparator(sortType));
     }

     /**
      * Restores the working set filter from the persistence store.
      */
     protected void initWorkingSetFilter() {
         String workingSetName = settings.get(STORE_WORKING_SET);

         IWorkingSet workingSet = null;
         
         if (workingSetName != null && workingSetName.equals("") == false) { //$NON-NLS-1$
 IWorkingSetManager workingSetManager = getPlugin().getWorkbench()
                     .getWorkingSetManager();
             workingSet = workingSetManager.getWorkingSet(workingSetName);
         } else if (PlatformUI
                 .getPreferenceStore()
                 .getBoolean(
                         IWorkbenchPreferenceConstants.USE_WINDOW_WORKING_SET_BY_DEFAULT)) {
             // use the window set by default if the global preference is set
 workingSet = getSite().getPage().getAggregateWorkingSet();
         }

         if (workingSet != null) {
             // Only initialize filter. Don't set working set into viewer.
 // Working set is set via WorkingSetFilterActionGroup
 // during action creation.
 workingSetFilter.setWorkingSet(workingSet);
             internalSetWorkingSet(workingSet);
         }
     }

     /**
      * Returns whether the navigator selection automatically tracks the active
      * editor.
      *
      * @return <code>true</code> if linking is enabled, <code>false</code>
      * if not
      * @since 2.0 (this was protected in 2.0, but was made public in 2.1)
      */
     public boolean isLinkingEnabled() {
         return linkingEnabled;
     }

     /**
      * Brings the corresponding editor to top if the selected resource is open.
      *
      * @since 2.0
      */
     protected void linkToEditor(IStructuredSelection selection) {

         if (this != this.getSite().getPage().getActivePart())
             return;
         
         Object obj = selection.getFirstElement();
         if (obj instanceof IFile && selection.size() == 1) {
             IFile file = (IFile) obj;
             IWorkbenchPage page = getSite().getPage();
             IEditorPart editor = ResourceUtil.findEditor(page, file);
             if (editor != null) {
                 page.bringToTop(editor);
                 return;
             }
         }
     }

     /**
      * Creates the action group, which encapsulates all actions for the view.
      */
     protected void makeActions() {
         setActionGroup(new MainActionGroup(this));
     }

     /**
      * Restores the saved filter settings.
      */
     private void restoreFilters() {
         IMemento filtersMem = memento.getChild(TAG_FILTERS);

         if (filtersMem != null) { //filters have been defined
 IMemento children[] = filtersMem.getChildren(TAG_FILTER);

             // check if first element has new tag defined, indicates new version
 if (children.length > 0
                     && children[0].getString(TAG_IS_ENABLED) != null) {
                 ArrayList selectedFilters = new ArrayList ();
                 ArrayList unSelectedFilters = new ArrayList ();
                 for (int i = 0; i < children.length; i++) {
                     if (children[i].getString(TAG_IS_ENABLED).equals(
                             String.valueOf(true))) {
                         selectedFilters.add(children[i].getString(TAG_ELEMENT));
                     } else {
                         //enabled == false
 unSelectedFilters.add(children[i]
                                 .getString(TAG_ELEMENT));
                     }
                 }

                 /* merge filters from Memento with selected = true filters from plugins
                  * ensure there are no duplicates & don't override user preferences */
                 List pluginFilters = FiltersContentProvider.getDefaultFilters();
                 for (Iterator iter = pluginFilters.iterator(); iter.hasNext();) {
                     String element = (String ) iter.next();
                     if (!selectedFilters.contains(element)
                             && !unSelectedFilters.contains(element)) {
                         selectedFilters.add(element);
                     }
                 }

                 //Convert to an array of Strings
 String [] patternArray = new String [selectedFilters.size()];
                 selectedFilters.toArray(patternArray);
                 getPatternFilter().setPatterns(patternArray);

             } else { //filters defined, old version: ignore filters from plugins
 String filters[] = new String [children.length];
                 for (int i = 0; i < children.length; i++) {
                     filters[i] = children[i].getString(TAG_ELEMENT);
                 }
                 getPatternFilter().setPatterns(filters);
             }
         } else { //no filters defined, old version: ignore filters from plugins
 getPatternFilter().setPatterns(new String [0]);
         }
     }

    /**
     * Restores the state of the receiver to the state described in the specified memento.
     *
     * @param memento the memento
     * @since 2.0
     */
    protected void restoreState(IMemento memento) {
        TreeViewer viewer = getTreeViewer();
        IMemento frameMemento = memento.getChild(TAG_CURRENT_FRAME);

        if (frameMemento != null) {
            TreeFrame frame = new TreeFrame(viewer);
            frame.restoreState(frameMemento);
            frame.setName(getFrameName(frame.getInput()));
            frame.setToolTipText(getFrameToolTipText(frame.getInput()));
            viewer.setSelection(new StructuredSelection(frame.getInput()));
            frameList.gotoFrame(frame);
        } else {
            IContainer container = ResourcesPlugin.getWorkspace().getRoot();
            IMemento childMem = memento.getChild(TAG_EXPANDED);
            if (childMem != null) {
                ArrayList elements = new ArrayList ();
                IMemento[] elementMem = childMem.getChildren(TAG_ELEMENT);
                for (int i = 0; i < elementMem.length; i++) {
                    Object element = container.findMember(elementMem[i]
                            .getString(TAG_PATH));
                    if (element != null) {
                        elements.add(element);
                    }
                }
                viewer.setExpandedElements(elements.toArray());
            }
            childMem = memento.getChild(TAG_SELECTION);
            if (childMem != null) {
                ArrayList list = new ArrayList ();
                IMemento[] elementMem = childMem.getChildren(TAG_ELEMENT);
                for (int i = 0; i < elementMem.length; i++) {
                    Object element = container.findMember(elementMem[i]
                            .getString(TAG_PATH));
                    if (element != null) {
                        list.add(element);
                    }
                }
                viewer.setSelection(new StructuredSelection(list));
            }
        }
    }

    /**
     * Restores the linking enabled state.
     */
    private void restoreLinkingEnabled() {
        Integer val = memento
                .getInteger(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
        if (val != null) {
            linkingEnabled = val.intValue() != 0;
        }
    }

    /**
     * @see ViewPart#saveState
     */
    public void saveState(IMemento memento) {
        TreeViewer viewer = getTreeViewer();
        if (viewer == null) {
            if (this.memento != null) {
                memento.putMemento(this.memento);
            }
            return;
        }

        //save sorter
 memento.putInteger(TAG_SORTER, getComparator().getCriteria());

        //save filters
 String filters[] = getPatternFilter().getPatterns();
        List selectedFilters = Arrays.asList(filters);
        List allFilters = FiltersContentProvider.getDefinedFilters();
        IMemento filtersMem = memento.createChild(TAG_FILTERS);
        for (Iterator iter = allFilters.iterator(); iter.hasNext();) {
            String element = (String ) iter.next();
            IMemento child = filtersMem.createChild(TAG_FILTER);
            child.putString(TAG_ELEMENT, element);
            child.putString(TAG_IS_ENABLED, String.valueOf(selectedFilters
                    .contains(element)));
        }

        if (frameList.getCurrentIndex() > 0) {
            //save frame, it's not the "home"/workspace frame
 TreeFrame currentFrame = (TreeFrame) frameList.getCurrentFrame();
            IMemento frameMemento = memento.createChild(TAG_CURRENT_FRAME);
            currentFrame.saveState(frameMemento);
        } else {
            //save visible expanded elements
 Object expandedElements[] = viewer.getVisibleExpandedElements();
            if (expandedElements.length > 0) {
                IMemento expandedMem = memento.createChild(TAG_EXPANDED);
                for (int i = 0; i < expandedElements.length; i++) {
                    if (expandedElements[i] instanceof IResource) {
                        IMemento elementMem = expandedMem
                                .createChild(TAG_ELEMENT);
                        elementMem.putString(TAG_PATH,
                                ((IResource) expandedElements[i]).getFullPath()
                                        .toString());
                    }
                }
            }
            //save selection
 Object elements[] = ((IStructuredSelection) viewer.getSelection())
                    .toArray();
            if (elements.length > 0) {
                IMemento selectionMem = memento.createChild(TAG_SELECTION);
                for (int i = 0; i < elements.length; i++) {
                    if (elements[i] instanceof IResource) {
                        IMemento elementMem = selectionMem
                                .createChild(TAG_ELEMENT);
                        elementMem.putString(TAG_PATH,
                                ((IResource) elements[i]).getFullPath()
                                        .toString());
                    }
                }
            }
        }

        saveLinkingEnabled(memento);
    }

    /**
     * Saves the linking enabled state.
     */
    private void saveLinkingEnabled(IMemento memento) {
        memento.putInteger(
                IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR,
                linkingEnabled ? 1 : 0);
    }

    /**
     * Selects and reveals the specified elements.
     */
    public void selectReveal(ISelection selection) {
        StructuredSelection ssel = convertSelection(selection);
        if (!ssel.isEmpty()) {
            getViewer().getControl().setRedraw(false);
            getViewer().setSelection(ssel, true);
            getViewer().getControl().setRedraw(true);
        }
    }

    /**
     * Saves the filters defined as strings in <code>patterns</code>
     * in the preference store.
     */
    public void setFiltersPreference(String [] patterns) {

        StringBuffer sb = new StringBuffer ();

        for (int i = 0; i < patterns.length; i++) {
            if (i != 0) {
                sb.append(ResourcePatternFilter.COMMA_SEPARATOR);
            }
            sb.append(patterns[i]);
        }

        getPlugin().getPreferenceStore().setValue(
                ResourcePatternFilter.FILTERS_TAG, sb.toString());

        // remove value in old workbench preference store location
 IPreferenceStore preferenceStore = IDEWorkbenchPlugin.getDefault()
                .getPreferenceStore();
        String storedPatterns = preferenceStore
                .getString(ResourcePatternFilter.FILTERS_TAG);
        if (storedPatterns.length() > 0) {
            preferenceStore.setValue(ResourcePatternFilter.FILTERS_TAG, ""); //$NON-NLS-1$
 }
    }

    /**
     * @see IWorkbenchPart#setFocus()
     */
    public void setFocus() {
        getTreeViewer().getTree().setFocus();
    }

    /**
     * Note: For experimental use only.
     * Sets the decorator for the navigator.
     * <p>
     * As of 2.0, this method no longer has any effect.
     * </p>
     *
     * @param decorator a label decorator or <code>null</code> for no decorations.
     * @deprecated use the decorators extension point instead; see IWorkbench.getDecoratorManager()
     */
    public void setLabelDecorator(ILabelDecorator decorator) {
        // do nothing
 }

    /**
     * @see IResourceNavigator#setLinkingEnabled(boolean)
     * @since 2.1
     */
    public void setLinkingEnabled(boolean enabled) {
        this.linkingEnabled = enabled;

        // remember the last setting in the dialog settings
 settings.put(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR,
                enabled);

        // if turning linking on, update the selection to correspond to the active editor
 if (enabled) {
            IEditorPart editor = getSite().getPage().getActiveEditor();
            if (editor != null) {
                editorActivated(editor);
            }
        }
    }

    /**
     * Sets the resource sorter.
     *
     * @param sorter the resource sorter
     * @since 2.0
     * @deprecated as of 3.3, use {@link ResourceNavigator#setComparator(ResourceComparator)}
     */
    public void setSorter(ResourceSorter sorter) {
        TreeViewer viewer = getTreeViewer();
        ViewerSorter viewerSorter = viewer.getSorter();

        viewer.getControl().setRedraw(false);
        if (viewerSorter == sorter) {
            viewer.refresh();
        } else {
            viewer.setSorter(sorter);
        }
        viewer.getControl().setRedraw(true);
        settings.put(STORE_SORT_TYPE, sorter.getCriteria());

        // update the sort actions' checked state
 updateActionBars((IStructuredSelection) viewer.getSelection());
    }
    
    /**
     * Sets the resource comparator
     *
     * @param comparator the resource comparator
     * @since 3.3
     */
    public void setComparator(ResourceComparator comparator){
        TreeViewer viewer = getTreeViewer();
        ViewerComparator viewerComparator = viewer.getComparator();

        viewer.getControl().setRedraw(false);
        if (viewerComparator == comparator) {
            viewer.refresh();
        } else {
            viewer.setComparator(comparator);
        }
        viewer.getControl().setRedraw(true);
        settings.put(STORE_SORT_TYPE, comparator.getCriteria());

        // update the sort actions' checked state
 updateActionBars((IStructuredSelection) viewer.getSelection());
    }

    /*
     * @see org.eclipse.ui.views.navigator.IResourceNavigatorPart#setWorkingSet(IWorkingSet)
     * @since 2.0
     */
    public void setWorkingSet(IWorkingSet workingSet) {
        TreeViewer treeViewer = getTreeViewer();
        Object [] expanded = treeViewer.getExpandedElements();
        ISelection selection = treeViewer.getSelection();
        
        internalSetWorkingSet(workingSet);
        
        workingSetFilter.setWorkingSet(emptyWorkingSet ? null : workingSet);
        if (workingSet != null) {
            settings.put(STORE_WORKING_SET, workingSet.getName());
        } else {
            settings.put(STORE_WORKING_SET, ""); //$NON-NLS-1$
 }
        updateTitle();
        treeViewer.refresh();
        treeViewer.setExpandedElements(expanded);
        if (selection.isEmpty() == false
                && selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            treeViewer.reveal(structuredSelection.getFirstElement());
        }
    }

    /**
     * Set the internal working set fields specific to the navigator.
     *
     * @param workingSet
     * the new working set
     * @since 3.2
     */
    private void internalSetWorkingSet(IWorkingSet workingSet) {
        this.workingSet = workingSet;
        emptyWorkingSet = workingSet != null && workingSet.isAggregateWorkingSet()
                && workingSet.isEmpty();
    }

    /**
     * Updates the action bar actions.
     *
     * @param selection the current selection
     * @since 2.0
     */
    protected void updateActionBars(IStructuredSelection selection) {
        ResourceNavigatorActionGroup group = getActionGroup();
        if (group != null) {
            group.setContext(new ActionContext(selection));
            group.updateActionBars();
        }
    }

    /**
     * Updates the message shown in the status line.
     *
     * @param selection the current selection
     */
    protected void updateStatusLine(IStructuredSelection selection) {
        String msg = getStatusLineMessage(selection);
        getViewSite().getActionBars().getStatusLineManager().setMessage(msg);
    }

    /**
     * Updates the title text and title tool tip.
     * Called whenever the input of the viewer changes.
     * Called whenever the input of the viewer changes.
     *
     * @since 2.0
     */
    public void updateTitle() {
        Object input = getViewer().getInput();
        IWorkspace workspace = ResourcesPlugin.getWorkspace();
        IWorkingSet workingSet = workingSetFilter.getWorkingSet();

        if (input == null || input.equals(workspace)
                || input.equals(workspace.getRoot())) {
            setContentDescription(""); //$NON-NLS-1$
 if (workingSet != null) {
                setTitleToolTip(NLS.bind(ResourceNavigatorMessages.ResourceNavigator_workingSetToolTip, workingSet.getLabel()));
            } else {
                setTitleToolTip(""); //$NON-NLS-1$
 }
        } else {
            ILabelProvider labelProvider = (ILabelProvider) getTreeViewer()
                    .getLabelProvider();
            String inputToolTip = getFrameToolTipText(input);
            String text = labelProvider.getText(input);
            if(text != null) {
                setContentDescription(text);
            }
            if (workingSet != null) {
                setTitleToolTip(NLS.bind(ResourceNavigatorMessages.ResourceNavigator_workingSetInputToolTip, inputToolTip, workingSet.getLabel()));
            } else {
                setTitleToolTip(inputToolTip);
            }
        }
    }

    /**
     * Returns the action group.
     *
     * @return the action group
     */
    protected ResourceNavigatorActionGroup getActionGroup() {
        return actionGroup;
    }

    /**
     * Sets the action group.
     *
     * @param actionGroup the action group
     */
    protected void setActionGroup(ResourceNavigatorActionGroup actionGroup) {
        this.actionGroup = actionGroup;
    }

    /*
     * @see IWorkbenchPart#getAdapter(Class)
     */
    public Object getAdapter(Class adapter) {
        if (adapter == IShowInSource.class) {
            return getShowInSource();
        }
        if (adapter == IShowInTarget.class) {
            return getShowInTarget();
        }
        return null;
    }

    /**
     * Returns the <code>IShowInSource</code> for this view.
     */
    protected IShowInSource getShowInSource() {
        return new IShowInSource() {
            public ShowInContext getShowInContext() {
                return new ShowInContext(getViewer().getInput(), getViewer()
                        .getSelection());
            }
        };
    }

    /**
     * Returns the <code>IShowInTarget</code> for this view.
     */
    protected IShowInTarget getShowInTarget() {
        return new IShowInTarget() {
            public boolean show(ShowInContext context) {
                ArrayList toSelect = new ArrayList ();
                ISelection sel = context.getSelection();
                if (sel instanceof IStructuredSelection) {
                    IStructuredSelection ssel = (IStructuredSelection) sel;
                    for (Iterator i = ssel.iterator(); i.hasNext();) {
                        Object o = i.next();
                        if (o instanceof IResource) {
                            toSelect.add(o);
                        } else if (o instanceof IMarker) {
                            IResource r = ((IMarker) o).getResource();
                            if (r.getType() != IResource.ROOT) {
                                toSelect.add(r);
                            }
                        } else if (o instanceof IAdaptable) {
                            IAdaptable adaptable = (IAdaptable) o;
                            o = adaptable.getAdapter(IResource.class);
                            if (o instanceof IResource) {
                                toSelect.add(o);
                            } else {
                                o = adaptable.getAdapter(IMarker.class);
                                if (o instanceof IMarker) {
                                    IResource r = ((IMarker) o).getResource();
                                    if (r.getType() != IResource.ROOT) {
                                        toSelect.add(r);
                                    }
                                }
                            }
                        }
                    }
                }
                if (toSelect.isEmpty()) {
                    Object input = context.getInput();
                    if (input instanceof IAdaptable) {
                        IAdaptable adaptable = (IAdaptable) input;
                        Object o = adaptable.getAdapter(IResource.class);
                        if (o instanceof IResource) {
                            toSelect.add(o);
                        }
                    }
                }
                if (!toSelect.isEmpty()) {
                    selectReveal(new StructuredSelection(toSelect));
                    return true;
                }
                return false;
            }
        };
    }
}

